В рамках курса вы познакомитесь с принципами визуализации данных при помощи пакета ggplot2. Этот пакет реализует концепцию “грамматики графики” (grammar of graphics) - специального языка, позволяющего описать любую визуализацию данных. В этом блокноте мы покажем базовые элементы грамматики - геометрические объекты и эстетики, статистические преобразования, шкалы и координатные системы. Во второй части будут рассмотрены слои, а также вопросы визуализации категориальных данных.
Рекомендуем прочитать главу Data Visualization в книге R for Data Science и посмотреть примеры в R Graph Gallery.
library(tidyverse)
Познакомимся с набором данных о топливной эффективности автомобилей.
data(mpg)
head(mpg)
## # A tibble: 6 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manu~ f 21 29 p comp~
## 3 audi a4 2 2008 4 manu~ f 20 31 p comp~
## 4 audi a4 2 2008 4 auto~ f 21 30 p comp~
## 5 audi a4 2.8 1999 6 auto~ f 16 26 p comp~
## 6 audi a4 2.8 1999 6 manu~ f 18 26 p comp~
Этот набор данных содержит сведения о топливной эффективности различных моделей автомобилей, собранных агентством EPA. Посмотреть описание столбцов набора данных можно выполнив команду: ?mpg. В этом блоконоте мы будем использовать некоторые из переменных данного набора - пробег на 1 галлоне топлива по трассе (hwy), объем двигателя в литрах (displ), тип привода (drv), число цилиндров двигателя (cyl).
Грамматика графики, реализованная в ggplot2, позволяет связать (map) столбцы набора данных с характеристиками геометрических объектов, которые используются для визуализации данных.
Геометрические объекты (geom) - это точки, столбцы, линии, полигоны и др. Характеристиками этих объектов являются положение (x и y), цвет, размер, заливка, символ, прозрачность и т.п. В ggplot2 визуальные характеристики называются эстетиками (aesthetics).
Таким образом, чтобы построить график, необходимо как минимум:
Связывание столбцов с визуальными характеристиками
Вот минимальный шаблон графика:
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))
Применим этот шаблон, чтобы изучить зависимость пробега по шоссе на одном галлоне (hwy) от объема двигателя (displ). Мы построим диаграмму рассеяния, элементами которой являются точки (geom_point):
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))
Замечания:
Набор данных для графика можно указать в аргументах функции ggplot().
Геометрические объекты добавляются на график как отдельные слои, с помощью оператора +. Здесь мы добавили только один слой. Обратите внимание, что при добавлении слоя знак + должен быть в конце первой строки, а не в начале второй.
Для слоя необходимо связать эстетики и столбцы таблицы данных, задав соответствие при помощи аргумента mapping= и функции aes(). Здесь мы связали положение точки - x и y со столбцами displ и hwy.
Внутри функции aes() вы можете использовать имена столбцов набора данных напрямую, без префикса и $.
Всегда используйте для связывания только столбцы из таблицы, которая указана как источник данных для графика. Не стоит использовать не включенные в эту таблицу данные (отдельные векторы или столбцы других таблиц).
У каждого геометрического объекта есть свой набор эстетик, которые можно использовать для визуализации данных. Доступные варианты можно посмотреть в справке - ?geom_point.
Например, для точек можно использовать следующие эстетики:
x, y),alpha),colour),shape),size), и др.Используем дополнительные эстетики, чтобы отобразить более сложную зависимость между переменными в наборе данных:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy,
colour = drv))
Связав тип привода drv с цветом, мы можем видеть более сложные зависимости. Например, что среди машин с объемом двигателя до 4 литров почти нет заднеприводных (drv = 'r'), или что при равном объеме двигателя полноприводные автомобили (drv = '4') имеют меньший пробег на 1 галлоне топлива.
Вы можете подобрать любые сочетания эстетик для визуализации своих данных, однако стоит помнить о том, что сложность этих эстетик для восприятия разная. Человеку легче всего сравнивать расположение и линейные размеры объектов. А оттенки цвета люди различают плохо. Поэтому стоит помнить правило:
Самые важные переменные следует связывать с эстетиками положения.
Эстетики можно условно разделить на два вида: количественные, пригодные для отображения количественных данных и качественные, пригодные для отображения категорий.
Количественные и качественные эстетики
В gglot2 вы можете связывать данные с какими угодно эстетиками, однако если, например связать категориальную переменную (фактор) с количественной эстетикой (размер), то вы получите предупреждение. Цвет можно связывать как с количественными, так и с категориальными переменными, при этом будет выбрана подходящая цветовая шкала.
В этом упражнении вы будете работать с набором данных о характеристиках и стоимости бриллиантов.
data(diamonds)
head(diamonds)
## # A tibble: 6 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
С описанием набора можно познакомиться в справке: ?diamonds.
Ваша задача - повторить визуализацию, показанную на рисунке.
Визуализация зависимости цены бриллианта от его характеристик
Совет: вы можете открыть график в новом окне, кликнув по ссылке на него с нажатой клавшией Shift. Если RStudio жалуется на отсутствующий файл, - выполните команду меню: Session/Set Working Directory/To Source File Location, чтобы установить в качестве рабочей директории папку, в которой находится данный блокнот.
# Раскомментируйте и допишите этот код:
#ggplot(data = ___) +
# geom_point(mapping = aes(x = ____,
# y = ____,
# ______))
In this exercise you will work with a dataset on diamonds characteristics and prices.
data(diamonds)
head(diamonds)
## # A tibble: 6 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
To see description of the dataset use: ?diamonds.
Your objective is to re-create the visualization shown below as close as possible:
Diamond prices vs its properties
Tip you can enlarge the picture by Shift-clicking its link. If RStudio complains about a missing file - select Session/Set Working Directory/To Source File Location command in the menu. This will set the current directory to the one which contains the source file.
# uncomment the following code and fill in the gaps:
#ggplot(data = ___) +
# geom_point(mapping = aes(x = ____,
# y = ____,
# ______))
Когда эстетика связывается со столбцом данных, значение в этом столбце определяет значение эстетики (level). Однако иногда необходимо вместо связывания (mapping) использовать явное определение (setting) значений эстетики. В этом случае у всех графических элементов значение эстетики будет одинаковым, - таким как вы зададите.
Чтобы явно определить значение эстетики, необходимо задать это значение вне функции aes(). Как правило, при определении эстетик используются константы.
# Связывание цвета с переменной
ggplot(data = mpg) +
geom_point(mapping =
aes(x = displ,y = hwy,
color = drv)) # внутри aes()!
# Определение цвета
ggplot(data = mpg) +
geom_point(mapping =
aes(x = displ, y = hwy),
color = 'blue') # вне aes()!
Если случайно попытаться определить значение эстетики внутри функции aes(), то можно получить неожиданный результат:
ggplot(data = mpg) +
geom_point(mapping =
aes(x = displ, y = hwy,
color = 'blue')) # ошибка: внутри aes()!
Здесь вместо определения цвета точек произошло по ошибке связывание цвета с константой 'blue'. Однако при связывании ggplot2 самостоятельно определяет, какие цвета будут соответствовать каким значениям, поэтому мы и получили такой результат.
В этом упражнении продолжите работу с набором данных diamonds.
Постройте визуализацию зависимости цены бриллианта от его веса и класса огранки (cut), запустив следующий блок кода.
# Измените код, чтобы задать прозрачность всех точек 5%
ggplot(data = diamonds) +
geom_point(mapping =
aes(x = carat, y = price,
colour = cut))
Точки на графике плохо различимы из-за наложения. Ваша задача - сделать точки полупрозрачными (прозрачность - 5%, или 0.05).
In this exercise you’ll continue to explore the diamonds dataset
First, visualize the relationship between diamond’s price, weight and cut by running the next code chunk.
# Измените код, чтобы задать прозрачность всех точек 5%
ggplot(data = diamonds) +
geom_point(mapping =
aes(x = carat, y = price,
colour = cut))
As you can see, the points overlap a lot and it’s hard to see, where the bulk of data lies. Your objective is to imporve the visualization by setting point opacity about .05 (5%). Opacity is controlled by alpha aesthetic.
Геомы (geom) - это геометрические объекты, которые используются для визуализации данных на графике. Можно рассматривать их как разные способы визуализации данных. Например, на диаграмме рассеяния для визуализации используются точки (geom_point()), на ящичной диаграмме - ящики (geom_boxplot()), на гистограмме или столбиковой диаграмме - столбики (geom_bar()).
В ggplot2 поддерживается большое количество типов визуализации, реализованных в виде функций geom_...(). Вы можете добавлять геомы к своей визуализации как отдельные слои.
Со списком доступных геомов можно познакомиться:
или в шпаргалке по ggplot2.
Шпаргалка всегда доступна в меню RStudio: Help>Cheatsheets>Data visualization with ggplot2.
В этом блокноте мы рассмотрим несколько геомов, которые можно использовать для визуализации распределений количественных переменных.
Гистограммы применяются для визуализации распределений количественных переменных. В ggplot2 для построения гистограмм используется функция geom_histogram(). Гистограмма - одномерный способ визуализации данных, поэтому при связывании эстетик с данными требуется указать только одну эстетику положения - x.
ggplot(data = mpg) +
geom_histogram(mapping = aes(x = hwy))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Для построения гистограммы используется группировка данных в интервалы. По умолчанию количество интервалов выбирается равным 30, однако часто требуется скорректировать количество интервалов, чтобы сделать визуализацию распределения более наглядной. При уменьшении количества интервалов, что эквивалентно увеличению их ширины, степень сглаживания данных возрастает.
Для настройки интервалов используются два аргумента функции geom_histogram():
bins (количество интервалов, ширина определяется автоматически) иbinwidth (ширина интервала, количество определяется автоматически).Кроме того, можно передать вектор с явно заданными границами интервалов через аргумент breaks.
ggplot(data = mpg) +
geom_histogram(mapping = aes(x = hwy),
binwidth = 2)
Рассмотрим предыдущий график подробнее. На горизонтальной оси отображены значения переменной hwy, которую мы связали с эстетикой положения x. Однако на вертикальной оси мы видим переменную count (число наблюдений на интервале), которой не было в исходном наборе данных:
names(mpg)
## [1] "manufacturer" "model" "displ" "year"
## [5] "cyl" "trans" "drv" "cty"
## [9] "hwy" "fl" "class"
Причина в том, что часто для визуализации исходные данные подвергаются преобразованиям. В нашем примере потребовалось разбить диапазон значений переменной hwy на интервалы заданной ширины и подсчитать количество наблюдений на каждом интервале.
Применение статистической функции
В ggplot2 любой геом связан с некоторым статистическим преобразованием (stat), которое применяется к данным. Например, в справке по ?geom_histogram можно убедиться, что по умолчанию для этого геома используется статистическое преобразование - группировка в интервалы (binning): stat = 'bin'.
Статистические преобразования доступны в виде отдельных функций.
Имена статистических функций полезно знать, чтобы смотреть по ним справку. Также их можно добавлять как слои на визуализацию, т.к. каждая статистика связана по умолчанию с определенным геомом.
Имена этих функций формируются по шаблону: stat_...(). Например, функция для группировки в интервалы назыавется: stat_bin().
В справке ?stat_bin можно посмотреть, какие показатели (Computed variables) вычисляет эта функция:
count - количество наблюдений на интервале (частота),density - плотность вероятности (площадь под кривой плотности = 1),ncount - нормированная частота, такая что максимальное значение частоты = 1 (удобно для сравнения распределений),ndensity - нормированная плотность.Вычисленные показатели можно связывать с эстетиками. При этом, чтобы отличать их от переменных в исходном наборе данных, необходимо в начале и в конце имени вычисленного показателя добавлять ..:
ggplot(data = mpg) +
geom_histogram(mapping =
aes(x = hwy, y = ..density..),
binwidth = 2)
Замечание: плотность вероятности выгодно отличается от частоты тем, что значения на оси y не зависят от заданной ширины интервалов:
\[ d_i = \frac{n_i}{N \cdot \Delta_i} \]
В то время как при использовании частот, чем шире интервалы - тем выше частота.
Плотность распределения вычисленную эмпирически на основе данных, можно сравнивать с плотностью какого-либо предполагаемого распределения, например нормального. Как это сделать - можно посмотреть в блокноте plotting_functions.Rmd.
Используя набор данных diamonds, постройте гистограмму веса бриллиантов (carat). На гистограмме должна отражаться нормированная частота. Подберите ширину интервала, которая, на ваш взгляд, хорошо подходит к этим данным (достаточное сглаживание, нет пустых интервалов).
# Раскомментируйте и дополните код:
#ggplot(data = diamonds) +
# geom_histogram(aes(x = ___, y = ___),
# binwidth = ___)
Using the diamonds dataset, plot a histogram for carat. Use the normalized count (i.e. the maximum count is 1). Adjust the binwith to your liking. Strive to a ‘smooth’ plot without big gaps but retaining the shape of distribution.
# Uncomment the code and fill in the gaps:
#ggplot(data = diamonds) +
# geom_histogram(aes(x = ___, y = ___),
# binwidth = ___)
Шкалы (scales) в ggplot2 определяют, как именно соотносятся значения в данных и визуальные характеристики геометрических элементов. Например, какой цвет должен соответствовать огранке бриллианта Ideal, или в каком месте координатной оси должна располагаться точка со значением переменной carat = 2. В зависимости от типа визуализируемой переменной, ggplot2 автоматически добавляет для нее дискретную (discrete) или непрерывную (continuous) шкалу, поэтому при разведочном анализе можно не заботиться о настройке шкал.
Однако настройка шкал позволяет сделать визуализацию более понятной, поэтому она часто нужна, когда вы хотите опубликовать свою визуализацию, или показать ее другим людям.
Вы можете:
- использовать нелинейную (например, логарифмическую) шкалу для визуализации данных,
- выбрать диапазон данных для визуализации, чтобы исключить выбросы, - изменить цветовую палитру графика, - задать шаг сетки и формат делений оси, - упорядочить категории на визуализации и в легенде.
Здесь мы рассмотрим только самые необходимые возможности. Более подробно со шкалами можно познакомиться в книге R for Data Science.
Часто встречаются данные с асимметричным распределением. Из-за наличия выбросов (очень больших значений), основная масса наблюдений оказывается “прижатой” к началу координат и детали формы распределения не видны. Логарифмирование за счет “сжатия” шкалы позволяет лучше видеть форму распределения.
# В исходной шкале
ggplot(data = diamonds) +
geom_histogram(mapping = aes(x = price), bins = 20)
# В логарифмической шкале
ggplot(data = diamonds) +
geom_histogram(mapping = aes(x = price), bins = 20) +
scale_x_log10()
Ранее вы построили визуализацию зависимости цены бриллианта от веса для разных классов огранки. Разброс значений цен и веса бриллиантов очень большой, а зависимость цены от веса - нелинейная. Ваша задача - попробовать “распрямить” эту зависимость за счет использования нелинейной шкалы.
# Используйте нелинейные шкалы, чтобы "распрямить" зависимость
ggplot(data = diamonds) +
geom_point(mapping =
aes(x = carat, y = price,
colour = cut))
Подсказки:
scale_x_...(), scale_y_...()).scale_..._log10()) или квадратного корня (scale_..._sqrt())You’ve observed that the visualization of price, weight and cut relationship demonstrated a huge variation in prices and weights. Also it could be noted, that the trend line for this relationship is non-linear. Your objective now is to try to ‘straighten’ that relationship by applying non-linear scales.
# Use non-linear scales on x and/or y axes to linearize the relationship
ggplot(data = diamonds) +
geom_point(mapping =
aes(x = carat, y = price,
colour = cut))
Tips:
scale_x_...(), scale_y_...()).scale_..._log10()) or square root transformations (scale_..._sqrt())В Приложении 1 рассмотрены вопросы выбора цветовой палитры и настройки шага сетки и делений шкалы. В Приложении 2 показано, как выбрать области данных для визуализации.
Шкалы связывают значения в таблице данных с положением геомов в некоторой системе координат. Однако чтобы увидеть данные, необходимо еще спроецировать эту систему координат на экран. Для этого в ggplot2 используются координатные системы (coord_...()).
В большинстве случаев подходит выбранная по умолчанию система координат. Здесь мы рассмотрим несколько случаев, когда может потребоваться ее поменять.
В наборе данных airports содержится список аэропортов США с географическими координатами - широтой и долготой.
library(nycflights13)
## Warning: package 'nycflights13' was built under R version 3.5.1
head(airports)
## # A tibble: 6 x 8
## faa name lat lon alt tz dst tzone
## <chr> <chr> <dbl> <dbl> <int> <dbl> <chr> <chr>
## 1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/New~
## 2 06A Moton Field Municipal ~ 32.5 -85.7 264 -6 A America/Chi~
## 3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/Chi~
## 4 06N Randall Airport 41.4 -74.4 523 -5 A America/New~
## 5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/New~
## 6 0A9 Elizabethton Municipal~ 36.4 -82.2 1593 -5 A America/New~
Попробуем визуализировать эти данные на диаграмме рассеяния:
ggplot(data = airports) +
geom_point(mapping = aes(x = lon, y = lat, color = factor(tz)))
Форма американского континента выглядит странно, поскольку использование географических координат (на глобусе) в качестве декартовых координат (на плоскости) - грубое приближение. Чтобы получить привычный вид карты, необходимо выбрать координатную систему, которая выполняет картографическую проекцию этих данных.
ggplot(data = airports) +
geom_point(mapping = aes(x = lon, y = lat, color = factor(tz))) +
coord_quickmap()
Теперь очертания континента более узнаваемы.
С помощью ggplot2 можно сделать и настоящую карту - см. ресурсы:
Встроенные геомы ggplot2 - например, столбиковые диаграммы, предполагают, что категориальные переменные всегда расположены по оси x. Это может быть неудобно из-за наложения меток категорий. Вы можете транспонировать оси координат, чтобы метки располагались на вертикальной оси и их можно было прочитать легко.
# Стандартное расположение - категории по оси X
ggplot(data = mpg) +
geom_bar(mapping = aes(x = manufacturer))
# Транспонирование
ggplot(data = mpg) +
geom_bar(mapping = aes(x = manufacturer)) +
coord_flip()
В приложении 2 рассмотрен пример масштабирования области графика с помощью шкал и координатной системы.
Более подробно можно познакомиться с координатными системами в руководстве по ggplot2.
Сравнение групп по некоторому количественному показателю - это часто используемый прием анализа зависимостей. Мы рассмотрим несколько способов сравнения групп.
Ящичные диаграммы (box plot) позволяют представить форму распределения количественной переменной в компактной форме и очень удобны для сравнения групп. В качестве примера, сравним топливную эффективность автомобилей с разным типом привода.
ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = drv, y = hwy))
Обратите внимание, что категориальная переменная должна обязательно связываться с эстетикой x, а количественная - с y. При необходимости, вы можете развернуть ящики с помощью coord_flip().
В ggplot2 для построения ящичных диаграмм обяазательно надо указывать обе эстетики - x (переменная, которая задает группы) и y (количественный показатель для сравнения). Поэтому ящичную диаграмму без разделения на группы построить нельзя. Но можно “обмануть” программу, задав в качестве переменной для группировки константу.
ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = '', y = hwy)) +
coord_flip()
Полигон частот (frequency polygon) - это аналог гистограммы, однако вместо столбиков в нем используются линии. Это позволяет сравнивать на одном графике несколько распределений. Необходимо использовать geom_freqpoly() и связывать количественный показатель с эстетикой x, а категориальную переменную - с color.
ggplot(data = mpg) +
geom_freqpoly(mapping = aes(x = hwy, color = drv),
bins = 15)
По умолчанию, график строится по абсолютным частотам. Это неудобно, когда количество наблюдений в подгруппах сильно различается, малочисленные группы “прижимаются” к горизонтальной оси. Для более наглядного сравнения можно использовать либо нормированные частоты, либо посчитать относительные частоты наблюдений.
При нормировке каждый полигон масштабируется таким образом, чтобы максимальная частота была равной 1.
ggplot(data = mpg) +
geom_freqpoly(mapping = aes(x = hwy, y = ..ncount..,
color = drv),
bins = 15)
При использовании относительных частот необходимо посчитать, какую долю составляет частота на интервале относительно общего количества наблюдений (в подгруппе). В ggplot2 относительная частота не вычисляется отдельно, но ее легко получить на основе других показателей, вычисленныйх статистикой stat_bin().
ggplot(data = mpg) +
geom_freqpoly(mapping =
aes(x = hwy,
y = ..count.. / sum(..count..), # доля от общего числа наблюдений
color = drv),
bins = 15)
Еще одним способом анализа зависимостей в ggplot2 является расщепление на панели (faceting). Вы можете разделить набор данных на подгруппы по значению одной или двух категориальных переменных. После этого для каждой группы будет построен отдельный график.
facet_wrap()Когда переменная для расщепления одна, удобно использовать функцию facet_wrap(). Используем ее для сравнения гистограмм распределений топливной эффективности автомобилей с разным типом привода. Гистограммы удобнее сравнивать, когда они расположены одна под другой, поэтому мы ограничим число столбцов одним с помощью аргумента ncol =. Вспомним также о необходимости нормировки частот.
ggplot(data = mpg) +
geom_histogram(mapping =
aes(x = hwy, y = ..ncount..),
# или: y = ..count.. / sum(..count..)
bins = 15) +
facet_wrap(~ drv, ncol = 1)
Сравнивая гистограммы распределений на панелях, мы видим, что эффективность машин с передним приводом (f) выше, а полноприводные машины (4) имеют меньший пробег на галлоне топлива. Таким образом, здесь мы видим связь объясняющей переменной (drv) и зависимой переменной (hwy).
Замечание: обратите внимание на необходимость добавить тильду ~ перед именем переменной для расщепления. Вообще, в синтаксисе формул R принято, что справа от тильды указывается объясняющая переменная (фактор).
facet_grid()Расщепление на панели можно сделать и по двум переменным. В этом случае, необходимо использовать функцию facet_grid(). В качестве аргумента, этой функции надо передать формулу вида: a ~ b, где a - переменная, по которой будут формироваться строки, а b - переменная для формирования столбцов.
В качестве примера, изучим зависимость цены от веса бриллианта в категориях с различной огранкой и прозрачностью.
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price)) +
facet_grid(cut ~ clarity)
Используя набор данных mpg, сравните топливную эффективность автомобилей на трассе (hwy) в зависимости от класса машины (class) и типа привода (drv). Какой из рассмотренных в этом разделе способов лучше всего подходит для этой задачи?
# Напишите свой код здесь:
Using the mpg dataset, compare the highway fuel economy (hwy) for different car classes (class) and drive types (drv). What visualization method is the most appropriate for this task?
# Write your code here:
При связывании переменных с эстетиками цвета fill или color в зависимости от вида переменной - непрерывная или дискретная - выбирается автоматически цветовая шкала. Для непрерывных переменных используется градиент. Для дискретных переменных выбираются максимально отстоящие друг от друга на цветовом круге оттенки цвета (hue). В пакете ggplot2 используется цветовое пространство HCL.
Цветовой круг
Данный выбор не всегда является оптимальным.
Для визуализации данных был специально разработан набор цветовых шкал ColorBrewer (по фамилии разработчика - Cynthia Brewer). Шкалы разрабатывались, в первую очередь, для создания картограмм, однако их можно использовать для любых типов визуализаций. Шкалы разработаны с учетом того, что некоторые люди не различают определенные цвета.
В R эти шкалы реализованы в пакете RColorBrewer.
RColorBrewer::display.brewer.all()
Замечание: запись <имя пакета>::<имя функции> позволяет обращаться к функции, реализованной в пакете, не подключая весь пакет. Также вы можете таким образом уточнить, о какой функции идет речь, если несколько пакетов содержат функции с одинаковыми именами.
Все шкалы ColorBrewer делятся на 3 категории:
YlOrRd до Blues.Качественные (qualitative) - для неупорядоченных категориальных переменных. На рисунке это шкалы от Accent до Set3.
Двунаправленные (diverging) - для количественных переменных, имеющих некоторое “центральное значение” и направления больше/меньше от него. На рисунке это шкалы от Spectral до BrBG.
Шкалы обладают разной степенью цветовой насыщенности. Более “ядовитые” шкалы используются для небольших по размеру геомов - например, точек на диаграммах рассеяния. А для заливки больших площадей, - например, столбиков, - лучше подходят более спокойные оттенки.
Шкалы содержат дискретные цвета, поэтому при визуализации с их помощью непрерывные переменные необходимо дискретизировать (т.е. разбивать на интервалы).
В ggplot2 нужную цветовую шкалу для категориальных данных можно выбрать, используя функцию: scale_color_brewer() (для цвета границы) или scale_fill_brewer() (для цвета заливки). Показанное на рисунке имя шкалы надо указать в аргументе palette = этой функции.
См. также справку: ?scale_color_brewer.
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price,
color = clarity),
alpha = 0.1) +
scale_color_brewer(palette = "Accent") +
# не обязательно:
guides(color = # не хотим прозрачность в легенде
guide_legend(override.aes =
list(alpha = 1)))
Шкалы ColorBrewer создавались для визуализации дискретных значений - упорядоченных и неупорядоченных категорий. Однако их можно использовать и с непрерывными переменными. В ggplot2 есть две функции - scale_color_distiller() и scale_fill_distiller() - соответственно, для цвета границы и заливки. Эти функции позволяют применять шкалы ColorBrewer к непрерывным данным. Они интерполируют дискретные цвета, включенные в шкалу. Палитра задается через аргумент palette =.
ggplot(data = diamonds) +
geom_hex(mapping = aes(x = carat, y = price)) +
scale_fill_distiller(palette = "BuGn")
## Warning: package 'hexbin' was built under R version 3.5.1
Специально для непрерывных данных была разработана еще одна цветовая шкала - viridis. Эта шкала обеспечивает правильную передачу значений даже при черно-белой печати и при использовании людьми, не различающими некоторые цвета.
Для использования этой шкалы необходимо установить пакет viridis. После этого можно использовать функции: viridis::scale_fill_viridis(), viridis::scale_color_viridis().
ggplot(data = diamonds) +
geom_hex(mapping = aes(x = carat, y = price)) +
viridis::scale_fill_viridis()
Замечание: запись <имя пакета>::<имя функции> позволяет обращаться к функции, реализованной в пакете, не подключая весь пакет. Также вы можете таким образом уточнить, о какой функции идет речь, если несколько пакетов содержат функции с одинаковыми именами.
Для настройки шага делений и меток делений шкалы в ggplot2 используются аргументы breaks и labels соответственно.
Требуется задать шаг делений вертикальной оси 5 единиц:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
scale_y_continuous(breaks = seq(15, 40, by = 5))
Требуется задать порядок категорий цветовой шкалы и определить понятные метки для категорий.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy,
colour = drv)) +
scale_color_discrete(breaks = c('f', 'r', '4'), # порядок
labels = c('Передний привод', # метки
'Задний привод',
'Полный привод'))
В ggplot2 есть два способа, с помощью которых можно задать пределы для координатных осей:
- с использованием шкалы,
- с использованием координатной системы.
При использовании шкалы происходит фильтрация исходных данных в заданных пределах и те точки, которые выходят за них, просто не попадают в визуализацию. При использовании координатной системы данные визуализируются полностью, однако те точки, которые выходят за пределы, остаются невидимыми.
# Исходный график
p <- ggplot(data = mpg,
mapping = aes(x = displ, y = hwy)) +
geom_point()
p
# Ограничение области визуализации с помощью шкалы
p + xlim(2, 4) + ylim(20, 35)
## Warning: Removed 114 rows containing missing values (geom_point).
# или + scale_x_continuous(limits = c(2, 4))
# Ограничение области визуализации с помощью координатной системы
p + coord_cartesian(xlim = c(2, 4), ylim = c(20, 35))
Хотя визуально графики не отличаются, на них отражен разный объем данных. Поэтому, если мы будем добавлять на визуализацию еще какие-нибудь слои, то результат может отличаться.
# Ограничение области визуализации с помощью шкалы
p + xlim(2, 4) + ylim(20, 35) +
geom_smooth(method = 'lm', se = FALSE, color = 'red')
## Warning: Removed 114 rows containing non-finite values (stat_smooth).
## Warning: Removed 114 rows containing missing values (geom_point).
# Ограничение области визуализации с помощью координатной системы
p + coord_cartesian(xlim = c(2, 4), ylim = c(20, 35)) +
geom_smooth(method = 'lm', se = FALSE, color = 'red')
Положение линий тренда на графиках отличается. На первом графике тренд построен только по тем данным, которые попали в окно диаграммы (остальные данные отфильтрованы). На втором - по всем данным, даже тем, которые на графике не видны.
Что же выбрать? Оба метода полезны в определенной ситуации. Например, если в ваших данных есть выбросы и вы не хотите, чтобы линии тренда или опорные линии (среднее, медиана) для этих данных смещались из-за них, то можно отфильтровать эти выбросы, задав пределы при помощи шкалы.
Если вы хотите получше рассмотреть какую-нибудь область графика, но при этом не хотите искажать статистики из-за фильтрации, то лучше использовать ограничение области просмотра с помощью координатной системы.
В ggplot2 оформление графиков можно гибко настраивать. Рекомендуем изучить раздел про оформление графиков в книге R for Data Science.
Здесь же мы покажем, как задать понятные подписи для графика. Это необходимо делать во всех графиках, которые вы намереваетесь кому-то показывать.
Для определения подписей на графике можно использовать функции, изменяющие отдельные элементы - например, xlab() - для изменения подписи для оси x. Но удобнее использовать функцию labs(), которая позволяет задать все подписи сразу.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy,
colour = drv)) +
scale_color_discrete(breaks = c('f', 'r', '4'),
labels = c('передний',
'задний',
'полный')) +
labs(title = 'Топливная эффективность автомобилей',
x = 'Объем двигателя, л',
y = 'Пробег на 1 галлоне топлива, миль',
color = 'Привод',
caption = 'Источник: fueleconomy.gov')